import axios, {
  AxiosError,
  type AxiosInstance,
  type AxiosRequestConfig,
  type AxiosResponse,
} from "axios";
import type { ApiResponse, ApiConfig } from "./types/index";
import { toUpperCamelCase, toLowerCamelCase } from "../utils/case";
// API Configuration
const API_BASE_URL = import.meta.env.DEV ? 'https://api.card.w520y.com' : '/';
const API_TIMEOUT = 30000; // 30 seconds
// Common Headers
const COMMON_HEADERS = {
  'Content-Type': 'application/json',
  'Accept': 'application/json',
};
// API Response Codes
const API_CODE = {
  SUCCESS: 200,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  SERVER_ERROR: 500,
};
const langSymbol = {
  "en": "en",
  "zh": "zh_cn",
  "tw": "zh_tw",
  "jp": "jp",
  "kr": "kr",
  "my": "my",
  "thai": "thai",
  "esp": "esp",
  "ind": "ind",
  "ar": "ar",
}
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
  retry?: boolean;
  retryCount?: number;
}

interface BaseResponse<T = any> {
  code: number;
  message: string;
  data: T;
}

class ApiClient {
  private client: AxiosInstance;
  private static instance: ApiClient;
  private isRefreshing = false;
  private refreshSubscribers: Array<(token: string) => void> = [];

  private constructor() {
    this.client = axios.create({
      baseURL: API_BASE_URL,
      timeout: API_TIMEOUT,
      headers: COMMON_HEADERS,
    });

    this.setupInterceptors();
  }

  public static getInstance(): ApiClient {
    if (!ApiClient.instance) {
      ApiClient.instance = new ApiClient();
    }
    return ApiClient.instance;
  }

  private setupInterceptors() {
    // Request interceptor
    this.client.interceptors.request.use(
      (config) => {
        if (config.headers?.skipAuth) {
          delete config.headers.skipAuth;
        }
        console.log("Request Config:", config);
        // 转换请求数据为大驼峰格式
        if (
          (config.data && typeof config.data === "object") ||
          (config.params && typeof config.params === "object")
        ) {
          const originalData =
            config.method === "get" ? config.params : config.data;
          const transformedData = toUpperCamelCase(originalData);
          if (config.method === "get") {
            config.params = transformedData;
          } else {
            config.data = transformedData;
          }
        }

        const token = localStorage.getItem("auth_token");
        if (token) {
          config.headers.Token = `${token}`;
        }

        const lang = localStorage.getItem("language") || 'en';
        if (lang) {
          let langSymbol = "en";
          if (lang === "en") {
            langSymbol = "en";
          } else if (lang === "zh") {
            langSymbol = "zh_cn";
          } else if (lang === "tw") {
            langSymbol = "zh_tw";
          } else if (lang === "jp") {
            langSymbol = "jp";
          } else if (lang === "kr") {
            langSymbol = "kr";
          } else if (lang === "my") {
            langSymbol = "my";
          } else if (lang === "thai") {
            langSymbol = "thai";
          } else if (lang === "esp") {
            langSymbol = "esp";
          } else if (lang === "ind") {
            langSymbol = "ind";
          } else if (lang === "ar") {
            langSymbol = "ar";
          }
          config.headers.lang = langSymbol;
        }

        // console.log('Final Config:', config);
        return config;
      },
      (error) => {
        // console.error('Request Interceptor Error:', error);
        return Promise.reject(error);
      }
    );

    // Response interceptor
    this.client.interceptors.response.use(
      (response: AxiosResponse<ApiResponse>) => {
        const { code, message, data } = response.data;
        console.log("API Response:", {
          url: response.config.url,
          method: response.config.method,
          status: response.status,
          code,
          message,
          data,
        });
        // console.log('Response Data:', response);
        if (code === API_CODE.SUCCESS) {
          // 转换响应数据为小驼峰格式
          const transformedData = toLowerCamelCase(response.data);
          return {
            ...response,
            data: transformedData,
          };
        }

        throw {
          code,
          message,
          details: data,
        };
      },
      async (error: AxiosError) => {
        console.error("Response Interceptor Error:", error);
        const originalRequest = error.config;

        // Handle token refresh
        if (
          error.response?.status === 401 &&
          originalRequest &&
          !originalRequest.headers?.skipRetry
        ) {
          if (!this.isRefreshing) {
            this.isRefreshing = true;
            try {
              const response = await this.client.post<{
                token: string;
                refreshToken: string;
              }>(
                "/api/v1/login/refresh",
                { refreshToken: localStorage.getItem("refresh_token") },
                { headers: { skipAuth: true } }
              );

              const { token, refreshToken } = response.data;
              localStorage.setItem("auth_token", token);
              localStorage.setItem("refresh_token", refreshToken);

              // Retry original request
              originalRequest.headers.Authorization = `Bearer ${token}`;
              originalRequest.headers.skipRetry = true;

              // Process refresh token subscribers
              this.refreshSubscribers.forEach((callback) => callback(token));
              this.refreshSubscribers = [];

              return this.client(originalRequest);
            } catch (refreshError) {
              // Clear tokens and redirect to login
              localStorage.removeItem("auth_token");
              localStorage.removeItem("refresh_token");
              window.location.href = "/login";
              throw refreshError;
            } finally {
              this.isRefreshing = false;
            }
          }

          // Queue request retry
          return new Promise((resolve) => {
            this.refreshSubscribers.push((token) => {
              originalRequest.headers.Authorization = `Bearer ${token}`;
              originalRequest.headers.skipRetry = true;
              resolve(this.client(originalRequest));
            });
          });
        }

        // Handle retry logic
        const shouldRetry =
          (error.config as CustomAxiosRequestConfig)?.retry &&
          (error.config as CustomAxiosRequestConfig).retryCount! > 0;
        if (shouldRetry) {
          (error.config as CustomAxiosRequestConfig).retryCount!--;
          return new Promise((resolve) => {
            setTimeout(() => {
              resolve(this.client(error.config!));
            }, 1000);
          });
        }

        throw error.response?.data || error;
      }
    );
  }

  public async get<T = any>(url: string, config?: ApiConfig): Promise<T> {
    const response = await this.client.get<BaseResponse<T>>(url, config);
    if (response.data.code !== API_CODE.SUCCESS) {
      throw response.data;
    }
    return response.data.data;
  }

  public async post<T = any>(
    url: string,
    data?: any,
    config?: ApiConfig
  ): Promise<T> {
    const response = await this.client.post<BaseResponse<T>>(url, data, config);
    if (response.data.code !== API_CODE.SUCCESS) {
      throw response.data;
    }
    return response.data.data;
  }

  public async put<T = any>(
    url: string,
    data?: any,
    config?: ApiConfig
  ): Promise<T> {
    const response = await this.client.put<BaseResponse<T>>(url, data, config);
    if (response.data.code !== API_CODE.SUCCESS) {
      throw response.data;
    }
    return response.data.data;
  }

  public async delete<T = any>(url: string, config?: ApiConfig): Promise<T> {
    const response = await this.client.delete<BaseResponse<T>>(url, config);
    if (response.data.code !== API_CODE.SUCCESS) {
      throw response.data;
    }
    return response.data.data;
  }

  public async patch<T = any>(
    url: string,
    data?: any,
    config?: ApiConfig
  ): Promise<T> {
    const response = await this.client.patch<BaseResponse<T>>(
      url,
      data,
      config
    );
    if (response.data.code !== API_CODE.SUCCESS) {
      throw response.data;
    }
    return response.data.data;
  }
}

export const apiClient = ApiClient.getInstance();
